 #include "classUART.h"
 #include "target.h"
typedef struct  
{
   unsigned char DLM;
   unsigned char DLL;
   unsigned char FDR;
   unsigned long int Rate;
}UartBaudStruct;
const UartBaudStruct StandardBaud[7] = {
      {0, 208,  33,   2400}, // 2400     Index = 0
      {0, 104,  33,   4800}, // 4800     Index = 1
      {0, 52,   33,   9600}, // 9600     Index = 2
      {0, 26,   33,  19200}, // 19200    Index = 3
      {0, 13,   33,  38400}, // 38400    Index = 4
      {0, 8,   133,  57600}, // 57600    Index = 5
      {0, 4,   133, 115200}  // 115200   Index = 6
      }; 

char const Div[FASize]= { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2/*1*/, 1, 2, 1, 2, 1, 3, 2, 3, 1, 4/*2*/,
                          3, 2, 3, 4, 1, 5, 4, 3, 5, 2/*3*/, 5, 3, 4, 5, 6, 7, 1, 8, 7, 6/*4*/,
                          5, 4, 7, 3, 8, 5, 7, 9, 2, 9/*5*/, 7, 5, 8,11, 3,10, 7,11, 4, 9/*6*/,
                          5,11, 6,13, 7, 8, 9,10,11,12/*7*/,13,14                               };
/**/
char const Mul[FASize]= { 1,15,14,13,12,11,10, 9, 8,15/*1*/, 7,13, 6,11, 5,14, 9,13, 4,15/*2*/,
                         11, 7,10,13, 3,14,11, 8,13, 5/*3*/,12, 7, 9,11,13,15, 2,15,13,11/*4*/,
                          9, 7,12, 5,13, 8,11,14, 3,13/*5*/,10, 7,11,15, 4,13, 9,14, 5,11/*6*/,
                          6,13, 7,15, 8, 9,10,11,12,13/*7*/,14,15                               };



/****************************************************************************************************/
/*                                                                                                  */
/*                                      C O N S T R U C T O R                                       */
/*                                                                                                  */
/****************************************************************************************************/
UART::UART(char s_port, char s_baud, Uint pclk)
{ 
  if(s_port>=NofUARTs)
    { fatal_err = true; uart = NO_SPort; }
   else
    {
      pclk=(( Fpclk / 16 ) / 9600);
      uart = s_port; fatal_err = grab = false;  baud = NoBaud; setBaud(s_baud,pclk);
      setWLength(DataBit8,StopBit1);  setParity(ParOFF,DfltParTyp);
      setFlowCtrl(RTSoff,CTSoff);     setFIFO(FIFOoff,DfltFIFORtr);
      Bsize = 0; pbufIN = pbufOUT = NULL;
      //if(!setBuffer(DfltBufSize)) fatal_err = true;
     }
//
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

UART::UART(char s_port, char s_baud, Uint pclk, char dbit, char sbit, bool par, char parTyp)
{
  if(s_port>=NofUARTs)
    { fatal_err = true; uart = NO_SPort; }
   else
    {
      pclk=(( Fpclk / 16 ) / 9600);
      uart = s_port; grab = false;     baud = NoBaud; setBaud(s_baud,pclk);
      if(dbit<DataBit5 || dbit>DataBit8) dbit = DataBit8;
      if(sbit<StopBit1 || sbit>StopBit2) sbit = StopBit1;
      setWLength(dbit,sbit);
      if(parTyp>=NofParTyps) parTyp = DfltParTyp;   setParity(par,parTyp);
      setFlowCtrl(RTSoff,CTSoff);     setFIFO(FIFOoff,DfltFIFORtr);
      Bsize = 0; pbufIN = pbufOUT = NULL;
      //if(!setBuffer(DfltBufSize)) fatal_err = true;
     }
//
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/




/****************************************************************************************************/
/*                                                                                                  */
/*                                       S E T    F U N C T I O N S                                 */
/*                                                                                                  */
/****************************************************************************************************/
bool UART::setBaud(char s_baud, Uint pclk)
{ 
  if(fatal_err) return false;
  switch(s_baud)
   {
     case(B1200)  : if(!calc_DLR_FDR(1200,pclk)) return false;   baud = s_baud;  break;
     case(B2400)  : if(!calc_DLR_FDR(2400,pclk)) return false;   baud = s_baud;  break;
     case(B4800)  : if(!calc_DLR_FDR(4800,pclk)) return false;   baud = s_baud;  break;
     case(B9600)  : if(!calc_DLR_FDR(9600,pclk)) return false;   baud = s_baud;  break;
     case(B19200) : if(!calc_DLR_FDR(19200,pclk)) return false;  baud = s_baud;  break;
     case(B38400) : if(!calc_DLR_FDR(38400,pclk)) return false;  baud = s_baud;  break;
     case(B57600) : if(!calc_DLR_FDR(57600,pclk)) return false;  baud = s_baud;  break;
     case(B115200): if(!calc_DLR_FDR(115200,pclk)) return false; baud = s_baud;  break;
     default:  return false;
   }
  return true;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

bool UART::setWLength(char data_bits, char stop_bits)
{ 
  if(fatal_err) return false;
  if(data_bits<DataBit5 || data_bits>DataBit8) return false;
  if(stop_bits<StopBit1 || stop_bits>StopBit2) return false;
  LCReg = LCReg&0xF8 | (data_bits-5) | (stop_bits-1<<2);
  //n_bit = data_bits;   n_S_bit = stop_bits;
  return true;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

bool UART::setParity(bool par, char parTyp)
{ 
  if(fatal_err) return false;
  if(parTyp>ParLOW) {return false;} else {LCReg = LCReg&0xCF | (parTyp<<4);}
  if(par) {LCReg |= 0x08;} else {LCReg &= 0xF7;}
  //parity = par; par_typ = parTyp;
  return true;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

bool UART::setFlowCtrl(bool rts_ctrl, bool cts_ctrl)
{ 
  if(fatal_err) return false;
  //if(uart!=SPort1) return false;
  if(rts_ctrl) {MCReg |= 0x40;} else {MCReg &= 0xBF;}
  if(cts_ctrl) {MCReg |= 0x80;} else {MCReg &= 0x7F;}
  //rts_auto = rts_ctrl; cts_auto = cts_ctrl;
  return true;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

bool UART::setFIFO(bool fifo_en, char fifoR_trg)
{ 
  if(fatal_err) return false;
  if(fifoR_trg>FIFOR14) {return false;} else {FCReg = /*FCReg&0x3F | */(fifoR_trg<<6);}
  if(fifo_en) {FCReg |= 0x01;} else {FCReg &= 0xFE;}
  return true;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

Uint UART::setBuffer(Uint size)
{ 
  if(pbufIN!=NULL)  { delete pbufIN;  pbufIN = NULL;  }
  if(pbufOUT!=NULL) { delete pbufOUT; pbufOUT = NULL; }
  if(!size) return 0;
  pbufIN = new char[size];
//  catch() { pbufIN = NULL; }
  
  
  
  pbufOUT = new char[size];
  //pbufIN = new char[size] throw(bad_alloc); pbufOUT = new char[size];
  if(pbufIN==NULL || pbufOUT==NULL)
    {size = Bsize; Bsize = 0; Bsize = setBuffer(size);}
   else
    {Bsize = size;}
  return Bsize;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/



/****************************************************************************************************/
/*                                                                                                  */
/*                     F U N C T I O N S    W O R K I N G    W I T H    U A R T                     */
/*                                                                                                  */
/****************************************************************************************************/
bool UART::grabUART(void)
{ 
  if(fatal_err) return false;
  switch(uart)
   {
     case(SPort0): //if(U0SCR) {return false;} else {U0SCR = 1;} 
       
       PINSEL0 |= 0x00000050;       /* RxD0 and TxD0 */            
                   U0LCR = 0x83;  U0DLL = StandardBaud[6].DLL; U0DLM = StandardBaud[6].DLM; U0FDR = StandardBaud[6].FDR;
                   U0FCR =  0x07;  U0LCR = 0x03;     grab = true;
                   
        U0IER = IER_RBR | IER_THRE | IER_RLS; /* Enable UART0 interrupt */
   if ( install_irq( UART0_INT, (void *)UART0_Handler, HIGHEST_PRIORITY ) == FALSE )
 {
    return (FALSE);
 }
                 //  U0LCR = LCReg|0x80;  U0DLL = (char)DLReg; U0DLM = DLReg>>8; U0FDR = FDReg;
                //   U0FCR = FCReg;  U0LCR &= 0x7F;     grab = true;
                 break;
     case(SPort1): //if(U1SCR) {return false;} else {U1SCR = 1;} 
                   U1LCR |= 0x80;  U1DLL = (char)DLReg; U1DLM = DLReg>>8; U1FDR = FDReg;
                   U1MCR = MCReg; U1LCR = LCReg; U1FCR = FCReg;    grab = true;
                 break;
     case(SPort2): //if(U2SCR) {return false;} else {U2SCR = 1;} 
                   U2LCR |= 0x80;  U2DLL = (char)DLReg; U2DLM = DLReg>>8; U2FDR = FDReg;
                   U2LCR = LCReg; U2FCR = FCReg;    grab = true;
                 break;
     case(SPort3): //if(U3SCR) {return false;} else {U3SCR = 1;} 
              //     U3LCR |= 0x80;  U3DLL = (char)DLReg; U3DLM = DLReg>>8; U3FDR = FDReg;
               //    U3LCR = LCReg; U3FCR = FCReg;   
              PINSEL0 |= 0x0000000A;       /* RxD0 and TxD0 */ 
                   U3LCR = 0x83;  U3DLL = StandardBaud[2].DLL; U3DLM = StandardBaud[2].DLM; U3FDR = StandardBaud[2].FDR; //FDR = FDReg;
                   U3FCR =  0x07;  U3LCR = 0x03;     grab = true;
                 
                   U3IER = IER_RBR | IER_THRE | IER_RLS; /* Enable UART0 interrupt */
//                   U3LCR = LCReg|0x80;  U3DLL = (char)DLReg; U3DLM = DLReg>>8; U3FDR = FDReg;
//                   U3FCR = FCReg;  U3LCR &= 0x7F;     grab = true;
   if ( install_irq( UART3_INT, (void *)UART3_Handler, HIGHEST_PRIORITY ) == FALSE )
 {
    return (FALSE);
 }        
                   
                   
                   grab = true;
                 break;
   }
  return true;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

bool UART::ungrabUART(void)
{ 
  if(fatal_err) return false;
  if(grab)
   { 
     switch(uart)
      {
        case(SPort0): U0SCR = 0; break;
        case(SPort1): U1SCR = 0; break;
        case(SPort2): U2SCR = 0; break;
        case(SPort3): U3SCR = 0; break;
       }
     grab = false;
    }
  return true;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/


bool UART::DTRon(void)
{ 
  if(fatal_err || !grab || uart!=SPort1 ) return false;
  MCReg |= 0x01;  U1MCR |= 0x01;
  return true;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

bool UART::DTRoff(void)
{ 
  if(fatal_err || !grab || uart!=SPort1 ) return false;
  MCReg &= 0xFE;  U1MCR &= 0xFE;
  return true;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

bool UART::RTS_on(void)
{ 
  if(fatal_err || !grab ) return false;
  switch(uart)
   {
     case(SPort0): RTS0on; break;
     case(SPort1): if(MCReg&0x40) return false;  U1MCR |= 0x02; break;
     case(SPort2): RTS2on; break;
     case(SPort3): RTS3on; break;
   }
  MCReg |= 0x02;
  return true;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

bool UART::RTS_off(void)
{ 
  if(fatal_err || !grab ) return false;
  switch(uart)
   {
     case(SPort0): RTS0off; break;
     case(SPort1): if(MCReg&0x40) return false;  U1MCR &= 0xFD; break;
     case(SPort2): RTS2off; break;
     case(SPort3): RTS3off; break;
   }
  MCReg |= 0x02;
  return true;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

bool UART::rstFIFOT(void)
{ 
  if(fatal_err || !grab ) return false;
  switch(uart)
   {
     case(SPort0): U0FCR |= 0x04; break;
     case(SPort1): U1FCR |= 0x04; break;
     case(SPort2): U2FCR |= 0x04; break;
     case(SPort3): U3FCR |= 0x04; break;
   }
  return true;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

bool UART::rstFIFOR(void)
{ 
  if(fatal_err || !grab ) return false;
  switch(uart)
   {
     case(SPort0): U0FCR |= 0x02; break;
     case(SPort1): U1FCR |= 0x02; break;
     case(SPort2): U2FCR |= 0x02; break;
     case(SPort3): U3FCR |= 0x02; break;
   }
  return true;
}
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/













bool UART::calc_DLR_FDR(Uint s_baud, Uint pclk)
{ Uint dl, modulo, ui1, min_modulo, min_ui1;

  min_modulo = s_baud; min_ui1 = 0;
  for(ui1=0; ui1<FASize; ++ui1)
   {
     dl = pclk*Mul[ui1]/16/s_baud/(Mul[ui1]+Div[ui1]);
     if(!dl) return false;  if(dl<3) break;
     modulo = pclk*Mul[ui1]/16/dl/(Mul[ui1]+Div[ui1])%s_baud;
     if(min_modulo>modulo) {min_modulo = modulo; min_ui1 = ui1;};
     if(min_modulo>s_baud-modulo) {min_modulo = s_baud-modulo; min_ui1 = ui1;};
     if(!min_modulo) break;
   }
  dl = pclk*Mul[min_ui1]/16/s_baud/(Mul[min_ui1]+Div[min_ui1]);
  if(dl>65535) {return false;} else {DLReg = dl;}
  FDReg = (Mul[min_ui1]<<4) | Div[min_ui1];
//  
  return true;
}













